package com.controller;

import com.service.MessageService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 在线对话控制层
 * 使用@ServerEndpoint注解实现WebSocket服务端
 */
@Component
@ServerEndpoint("/ws/chat/{userId}")
public class ChatWebSocket implements ApplicationContextAware {
    
    // 存储用户会话
    private static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();
    
    // Spring应用上下文，用于获取Bean
    private static ApplicationContext applicationContext;
    
    // 消息服务
    private MessageService messageService;

    @Override
    public void setApplicationContext(ApplicationContext context) {
        applicationContext = context;
    }

    // 连接建立时触发
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        sessionMap.put(userId, session);
        System.out.println("用户 " + userId + " 已连接，当前在线用户数：" + sessionMap.size());
        
        // 获取MessageService实例
        if (messageService == null && applicationContext != null) {
            messageService = applicationContext.getBean(MessageService.class);
        }
        
        // 通知其他用户有新用户上线
        broadcastMessage("系统消息：用户 " + userId + " 已上线", userId);
    }

    // 接收消息
    @OnMessage
    public void onMessage(String message, @PathParam("userId") String senderId) {
        System.out.println("收到用户 " + senderId + " 的消息：" + message);
        
        // 保存消息到数据库
        if (messageService != null) {
            try {
                messageService.saveMessage(message, senderId, "all");
            } catch (Exception e) {
                System.err.println("保存消息失败：" + e.getMessage());
            }
        }
        
        // 广播消息给所有用户
        broadcastMessage("用户 " + senderId + ": " + message, senderId);
    }

    // 连接关闭时触发
    @OnClose
    public void onClose(@PathParam("userId") String userId) {
        sessionMap.remove(userId);
        System.out.println("用户 " + userId + " 已断开连接，当前在线用户数：" + sessionMap.size());
        
        // 通知其他用户有用户下线
        broadcastMessage("系统消息：用户 " + userId + " 已下线", userId);
    }

    // 连接错误时触发
    @OnError
    public void onError(Session session, Throwable error) {
        System.err.println("WebSocket连接发生错误：" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 广播消息给所有用户（除了发送者）
     * @param message 消息内容
     * @param excludeUserId 排除的用户ID
     */
    private void broadcastMessage(String message, String excludeUserId) {
        sessionMap.forEach((userId, session) -> {
            if (!userId.equals(excludeUserId) && session.isOpen()) {
                try {
                    session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    System.err.println("发送消息失败：" + e.getMessage());
                    // 如果发送失败，可能是连接已断开，移除该会话
                    sessionMap.remove(userId);
                }
            }
        });
    }

    /**
     * 发送消息给指定用户
     * @param userId 用户ID
     * @param message 消息内容
     * @return 是否发送成功
     */
    public static boolean sendMessageToUser(String userId, String message) {
        Session session = sessionMap.get(userId);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
                return true;
            } catch (IOException e) {
                System.err.println("发送消息给用户 " + userId + " 失败：" + e.getMessage());
                sessionMap.remove(userId);
            }
        }
        return false;
    }

    /**
     * 获取当前在线用户数
     * @return 在线用户数
     */
    public static int getOnlineUserCount() {
        return sessionMap.size();
    }

    /**
     * 获取所有在线用户ID
     * @return 在线用户ID集合
     */
    public static java.util.Set<String> getOnlineUsers() {
        return sessionMap.keySet();
    }
}
